package com.jose.photogallery.domain;

import java.util.ConcurrentModificationException;
import java.util.logging.Logger;

import com.googlecode.objectify.ObjectifyOpts;

public class DAOT extends PhotogalleryDAO {
	private static final Logger log = Logger.getLogger(DAOT.class.getName());
	
	/** Alternate interface to runnable for executing transactions */
	public static interface Transactable {
		void run(DAOT daot);
	}
	
	/**
	 * Provides a place to put the result too. Note that the result
	 * is only valid if the transaction completes successfully; otherwise
	 * it should be ignored because it is not necessarily valid
	 */
	abstract public static class Transact<T> implements Transactable {
		protected T result;
		public T getResult() { return this.result; }
	}
	
	/** create a default DAOT and run the transaction through it */
	public static void runInTransaction(Transactable t){
		DAOT daot = new DAOT();
		daot.doTransaction(t);
	}
	
	/**
	 * Run this task through transactions until it succeeds without an optimistic
	 * concurrency failure.
	 */
	public static void repeatInTransaction(Transactable t){
		while(true) {
			try {
				runInTransaction(t);
				break;
			} catch (ConcurrentModificationException ex) {
				log.warning("Optimistic concurrency failure for " + t + ":" + ex);
			}
		}
	}
	
	/** Starts out with a transaction and session cache */
	public DAOT(){
		super(new ObjectifyOpts().setSessionCache(true).setBeginTransaction(true));
	}
	
	/** Adds transaction to whatever you pass in */
	public DAOT(ObjectifyOpts opts) {
		super(opts.setBeginTransaction(true));
	}
	
	/**
	 * Executes the task in the transactional context of this DAO/ofy
	 */
	public void doTransaction(final Runnable task){
		this.doTransaction(new Transactable() {
			@Override
			public void run(DAOT daot) {
				task.run();
			}
		});
	}
	
	/**
	 * Executes the task in the transactional context of this DAO/ofy
	 */
	public void doTransaction(Transactable task){
		try{
			task.run(this);
			ofy().getTxn().commit();
		} finally {
			if (ofy().getTxn().isActive())
					ofy().getTxn().rollback();
		}
	}
}
